#region Using directives

using System;
using System.Drawing;
using System.Reflection;
using System.IO;
using System.Windows.Forms;

using FighterChessEngine.Event;
using FighterChessEngine.Enum;
using FighterChessEngine.FC_Board;
using FighterChessEngine.FC_Fighter;
using FighterChessEngine.FC_Fighter.Fighters;
using FighterChessEngine.FC_Player;

using FighterChessSkin.FC_Fighter;
using FighterChessSkin.FC_Messenger;

#endregion

namespace FighterChessSkin.FC_Board
{
    /// <summary>
    /// Summary description for UIBoard.
    /// </summary>
    public class UIBoard
    {
        #region Atributes
        private readonly string appDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
        private readonly string boardDir = "Images\\Board";
        private readonly string boardBackground;
        private readonly int topReserve = 24;
        private readonly int width = 216;
        private readonly int height = 240;

        private Bitmap imgBoard;
        private Bitmap bmpOff;
        private Graphics gOn;
        private Graphics gOff;
        private Point location; // top - left
        private Board board;
        private UIFighter[,] uiFighters;
        private UISquare[,] uiSquares;
        #endregion

        #region Properties
        public Board Board
        {
            get { return board; }
            set
            {
                board = value;
                board.FighterMove += new Board.EventFighterMoveHandler(board_FighterMove);
                board.FighterSitDown += new Board.EventFighterSitDownHandler(board_FighterSitDown);
                board.FighterStandUp += new Board.EventFighterStandUpHandler(board_FighterStandUp);
                board.FighterRestoreHP += new Board.EventFighterRestoreHPHandler(board_FighterRestoreHP);
                board.FighterLevelUp += new Board.EventFighterLevelUpHandler(board_FighterLevelUp);
                board.FighterClicked += new Board.EventFighterClickedHandler(board_FighterClicked);
                board.FighterKilled += new Board.EventFighterKilledHandler(board_FighterKilled);
                board.FightersFight += new Board.EventFightersFightHandler(board_FightersFight);
                board.FighterMoveToRandomSquare += new Board.EventFighterMoveToRandomSquareHandler(board_FighterMoveToRandomSquare);
                board.GameOver += new Board.EventEndGameHandler(board_GameOver);
            }
        }

        public Graphics Graphic
        {
            get { return gOn; }
            set { gOn = value; }
        }
        #endregion

        #region Methods
        public UIBoard(Player p1, Player p2)
        {
            this.Board = new Board(p1, p2);

            boardBackground = appDir + "\\" + boardDir + "\\" + "board.png";
            Init();
        }

        public UIBoard(Board board)
        {
            this.Board = board;

            boardBackground = appDir + "\\" + boardDir + "\\" + "board.png";
            Init();
        }

        public void Draw()
        {
            DrawBackground();
            DrawSquares();
            DrawFighters();
            FlushBuffer();
        }

        public void Click(int xCoord, int yCoord)
        {
            Square clickedSquare = GetSquareAt(xCoord, yCoord);
            if (clickedSquare != null) // click inside board
            {
                board.Click(clickedSquare.Row, clickedSquare.Col);
            }
        }

        public Square GetSquareAt(int xCoord, int yCoord)
        {
            if (!Contains(xCoord, yCoord))
                return null;

            for (int row = 0; row < 8; row++)
                for (int col = 0; col < 8; col++)
                    if (uiSquares[row, col].Contains(xCoord, yCoord, this.location))
                        return board.Squares[row, col];

            return null;
        }

        public Fighter GetFighterAt(int xCoord, int yCoord)
        {
            Square s = GetSquareAt(xCoord, yCoord);
            if (s == null)
                return null;

            return board.Fighters[s.Row, s.Col] != null 
                ? board.Fighters[s.Row, s.Col]
                : null;
        }
        #endregion

        #region Events
        void board_FighterMove(Fighter fighter, EventMoveArgs e)
        {
            // hide flashing square before move
            HideFlashingSquare();
            // re-draw stand fighter
            uiFighters[e.Move.OldRow, e.Move.OldCol].DrawStandStance();
            FlushBuffer();

            // delete ui fighter at old pos
            uiFighters[e.Move.OldRow, e.Move.OldCol] = null;

            // create board img without fighter at old and new pos
            Bitmap bmpTempBoard;
            bmpTempBoard = CreateTempBoard();

            // make new ui fighter at new pos with sit stand 
            uiFighters[e.Move.NewRow, e.Move.NewCol] = new UIFighter(fighter, gOff);
            uiFighters[e.Move.NewRow, e.Move.NewCol].RequestFlushBuffer +=
                new UIFighter.EventRequestFlushBuffer(UIBoard_RequestFlushBuffer);
            uiFighters[e.Move.NewRow, e.Move.NewCol].RequestDrawBoard +=
                new UIFighter.EventRequestDrawBoard(UIBoard_RequestDrawBoard);

            // draw move in animation
            uiFighters[e.Move.NewRow, e.Move.NewCol].AnimationMove(e.Move, bmpTempBoard);
        }

        void board_FighterStandUp(Fighter fighter)
        {
            uiSquares[fighter.CurrentPos.Row, fighter.CurrentPos.Col].Draw();
            uiFighters[fighter.CurrentPos.Row, fighter.CurrentPos.Col].StandUp();
            FlushBuffer();
        }

        void board_FighterSitDown(Fighter fighter)
        {
            HideFlashingSquare();
            uiSquares[fighter.CurrentPos.Row, fighter.CurrentPos.Col].Draw();
            uiFighters[fighter.CurrentPos.Row, fighter.CurrentPos.Col].SitDown();
            FlushBuffer();

            DrawUpperSquare(fighter);
        }

        void board_FighterLevelUp(Fighter fighter, int increment)
        {
            uiFighters[fighter.CurrentPos.Row, fighter.CurrentPos.Col].LevelUp(increment);

            string mess = "I'm more POWERFUL now!!! (^__^)";
            frmMessageBox messageBox = new frmMessageBox(fighter, mess);
            messageBox.ShowDialog();
        }

        void board_FighterRestoreHP(Fighter fighter)
        {
            uiFighters[fighter.CurrentPos.Row, fighter.CurrentPos.Col].RestoreHP();

            string mess = "Ahhh!!! Feel so good ... (~__~)";
            frmMessageBox messageBox = new frmMessageBox(fighter, mess);
            messageBox.ShowDialog();
        }

        void board_FighterClicked(Fighter fighter)
        {
            // draw move path 
            uiFighters[fighter.CurrentPos.Row, fighter.CurrentPos.Col].ShowNextPosByFlashSquare(this.uiSquares);

            // if there are enemies in line, show them
            for (int row = 0; row < 8; row++)
                for (int col = 0; col < 8; col++)
                    if (uiSquares[row, col].Flashing && uiFighters[row, col] != null)
                        uiFighters[row, col].Draw();

            board_FighterStandUp(fighter);


            //Draw(); // draw fighter which changed stance
            //uiFighters[fighter.CurrentPos.Row, fighter.CurrentPos.Col].ShowNextPos(this.uiSquares);
            //DrawFighters();
            //FlushBuffer();
        }

        void board_FightersFight(Fighter attacker, Fighter defender)
        {
            // just call - do nothing
            uiFighters[attacker.CurrentPos.Row, attacker.CurrentPos.Col].Fight(
                uiFighters[defender.CurrentPos.Row, defender.CurrentPos.Col]);
        }

        void board_FighterKilled(Fighter victim, Fighter killer)
        {
            /*string mess = "AHHHHH!!! Bye bye my love ... [>\"<]";
            frmMessageBox messageBox = new frmMessageBox(victim, mess);
            messageBox.ShowDialog();*/
            
            HideFlashingSquare();

            uiFighters[victim.CurrentPos.Row, victim.CurrentPos.Col] = null;
            uiSquares[victim.CurrentPos.Row, victim.CurrentPos.Col].Draw();
            FlushBuffer();

            if (killer != null)
                DrawUpperSquare(killer);
            
            // King die
            
        }

        void board_FighterMoveToRandomSquare(Fighter fighter, SquareType fate)
        {
            string mess = "";
            switch (fate)
            {
                case SquareType.Die:
                    mess = "AHHHHHH!!!! Bye bye my love ... (+__+)";
                    break;
                case SquareType.HpRestore:
                    //board_FighterRestoreHP(fighter);
                    return;
                    //mess = "Ahhh!!! Feel so good ... (~__~)";
                    //break;
                case SquareType.LevelUp:
                    //board_FighterLevelUp(fighter, 0);
                    return;
                    ////mess = "I'm more POWERFUL now!!! (^__^)";
                    break;
                default: break;
            }

            frmMessageBox messageBox = new frmMessageBox(fighter, mess);
            messageBox.ShowDialog();
        }

        void board_GameOver(Player winner, Player loser)
        {
            string mess = "Winner : " + winner.Name + "\r\n";
            mess += "Loser: " + loser.Name;
            MessageBox.Show(mess);

            //UPGRADE// end game with end screen
        }

        void UIBoard_RequestFlushBuffer()
        {
            FlushBuffer();
        }

        void UIBoard_RequestDrawBoard()
        {
            Draw();
        }
        #endregion

        #region Support Funcs
        private void Init()
        {
            bmpOff = new Bitmap(width, height);
            gOff = Graphics.FromImage(bmpOff);
            location = new Point(12, 10); /*HARDCODE*/
            imgBoard = new Bitmap(boardBackground);

            InitUISquares();
            InitUIFighters();
        }

        private void InitUISquares()
        {
            uiSquares = new UISquare[8, 8];
            for (int row = 0; row < 8; row++)
                for (int col = 0; col < 8; col++)
                    uiSquares[row, col] = new UISquare(board.Squares[row, col], gOff, this.imgBoard);
        }

        private void InitUIFighters()
        {
            uiFighters = new UIFighter[8, 8];
            for (int row = 0; row < 8; row++)
                for (int col = 0; col < 8; col++)
                    if (board.Fighters[row, col] != null)
                    {
                        uiFighters[row, col] = new UIFighter(board.Fighters[row, col], gOff);
                        uiFighters[row, col].RequestDrawBoard += new UIFighter.EventRequestDrawBoard(UIBoard_RequestDrawBoard);
                        uiFighters[row, col].RequestFlushBuffer += new UIFighter.EventRequestFlushBuffer(UIBoard_RequestFlushBuffer);
                    }

        }

        private void FlushBuffer()
        {
            gOn.DrawImage(bmpOff, location.X, location.Y);
        }

        private void DrawBackground()
        {
            gOff.DrawImage((Image)imgBoard, 0, 0);
        }

        private void DrawFighters()
        {
            for (int row = 0; row < 8; row++)
                for (int col = 0; col < 8; col++)
                    if (uiFighters[row, col] != null)
                        uiFighters[row, col].Draw();
        }

        private void DrawSquares()
        {
            for (int row = 0; row < 8; row++)
                for (int col = 0; col < 8; col++)
                {
                    uiSquares[row, col].DrawBackground();
                    if (board.Squares[row, col].Type != SquareType.Normal)
                        uiSquares[row, col].DrawForeground();
                }
        }

        private void DrawTopReserve()
        {
            Rectangle rect = new Rectangle(0, 0, width, topReserve);
            gOff.DrawImage((Image)imgBoard, 0, 0, rect, GraphicsUnit.Pixel);
            FlushBuffer();
        }

        private void DrawTopReserveAt(int col)
        {
            int colWidth = width / 8;
            Rectangle rect = new Rectangle(col * colWidth, 0, colWidth, topReserve);
            gOff.DrawImage((Image)imgBoard, col * colWidth, 0, rect, GraphicsUnit.Pixel);
            FlushBuffer();
        }

        private void DrawUpperSquare(Fighter fighter)
        {
            int row = fighter.CurrentPos.Row;
            int col = fighter.CurrentPos.Col;
            if (row == 0)
            {
                //DrawTopReserve();
                DrawTopReserveAt(col);
                return;
            }
            else
            {
                uiSquares[row - 1, col].Draw();
                if (uiFighters[row - 1, col] != null)
                    uiFighters[row - 1, col].Draw();
                FlushBuffer();
            }
        }

        private Bitmap CreateTempBoard()
        {
            Bitmap bmpBoard;
            bmpBoard = new Bitmap(width, height);
            Graphics g = Graphics.FromImage((Image)bmpBoard);
            g.DrawImage((Image)this.imgBoard, 0, 0);
            for (int row = 0; row < 8; row++)
                for (int col = 0; col < 8; col++)
                {
                    uiSquares[row, col].Graphic = g;
                    uiSquares[row, col].Draw();
                    uiSquares[row, col].Graphic = gOff;
                    if (uiFighters[row, col] != null)
                    {
                        uiFighters[row, col].Graphic = g;
                        uiFighters[row, col].Draw();
                        uiFighters[row, col].Graphic = gOff;
                    }
                }
            g.Dispose();
            return bmpBoard;
        }

        private void HideFlashingSquare()
        {
            foreach (UISquare uis in uiSquares)
            {
                if (uis.Flashing)
                {
                    uis.ClearFlashing();
                    uis.Flashing = false;

                    if (uiFighters[uis.Row, uis.Col] != null)
                    {
                        uiFighters[uis.Row, uis.Col].Draw();
                        FlushBuffer();
                    }
                }
            }
            FlushBuffer();
        }

        private bool Contains(int xCoord, int yCoord)
        {
            return ((xCoord >= location.X && xCoord <= location.X + width)
                && (yCoord >= location.Y + topReserve && yCoord <= location.Y + height));
        }
        #endregion
    }
}
